import { isRoomInterval } from '@/ayaka'
import { ObserveTask, ObserveTaskType } from './types'
import SpawnController from '@/modules/structures/spawn'
import { CreepRoles } from '@/modules/structures/spawn/types'
import { scoutWork } from './scout'
import { RoomSafeState } from '@/room/state/types'

/**
 * 观察任务管理器
 */
export default class ObserveTaskManager {
    /**
     * 运行观察任务
     */
    public static run(room: MyRoom) {
        const memory = ObserveTaskManager.getMemory(room)

        const tasks = (memory.tasks = memory.tasks.filter((task) => {
            if (task.done || !task.roomNames.length) {
                const scouts = task.scouts.map((name) => Game.creeps[name]).filter(Boolean)
                scouts.forEach((scout) => delete scout.memory.taskId)
                return false
            }
            return true
        }))

        ObserveTaskManager.assignScout(room, tasks)
        ObserveTaskManager.execute(room, tasks)
    }

    /**
     * 获取 memory
     */
    public static getMemory(room: MyRoom) {
        if (!room.memory.observe) {
            room.memory.observe = {
                tasks: [],
            }
        }
        return room.memory.observe
    }

    /**
     * 获取指定房间的观察任务
     */
    public static getObserveTask(room: MyRoom) {
        const memory = ObserveTaskManager.getMemory(room)
        return memory.tasks
    }

    /**
     * 添加观察任务
     */
    public static addTask(room: MyRoom, task: ObserveTask) {
        const memory = ObserveTaskManager.getMemory(room)
        memory.tasks.push(task)
    }

    /**
     * 移除观察任务
     */
    public static removeTask(room: MyRoom, taskName: string) {
        const memory = ObserveTaskManager.getMemory(room)
        const index = memory.tasks.findIndex((task) => task.name === taskName)
        if (index >= 0) memory.tasks.splice(index, 1)
    }

    /**
     * 获取指定名字的观察任务
     */
    public static getTaskByName(room: MyRoom, taskName: string) {
        const memory = ObserveTaskManager.getMemory(room)
        return memory.tasks.find((task) => task.name === taskName)
    }

    /**
     * 获取指定类型的观察任务
     */
    public static getTasksByType(room: MyRoom, type: ObserveTaskType) {
        const memory = ObserveTaskManager.getMemory(room)
        return memory.tasks.filter((task) => task.type === type)
    }

    /**
     * 执行观察任务
     */
    protected static execute(room: MyRoom, tasks: ObserveTask[]) {
        tasks.forEach((task) => {
            scoutWork(room, task)
        })
    }

    /**
     * 分配 scout
     */
    protected static assignScout(room: MyRoom, tasks: ObserveTask[]) {
        if (!isRoomInterval(room, 11)) return

        const scouts = global.roleStats[room.name]?.scout || []
        const scoutSet = new Set(scouts.map((creep) => creep.name))
        const freeScouts = scouts.filter((creep) => !creep.memory.taskId)

        // 是否孵化过 scout
        let hasSpawn = false

        tasks.forEach((task) => {
            task.scouts = task.scouts.filter((name) => scoutSet.has(name))
            if (task.scouts.length) return

            // 找离任务地点最近的 scout
            const scout = freeScouts.reduce(
                (min, creep) => {
                    const distance = Game.map.getRoomLinearDistance(creep.room.name, task.roomNames[0])
                    if (distance < min.distance) {
                        return {
                            creep,
                            distance,
                        }
                    }
                    return min
                },
                { creep: null, distance: Infinity },
            ).creep

            if (scout) {
                scout.memory.taskId = task.name
                task.scouts.push(scout.name)
                return
            }

            if (!task.timeout) return

            // 有超时时间的任务比较紧急，直接孵化 scout
            ObserveTaskManager.spawnScout(room)
            hasSpawn = true

            if (task.timeout-- <= 0) {
                task.done = true
            }
        })

        if (!hasSpawn && !scouts.length && tasks.length) {
            ObserveTaskManager.spawnScout(room)
        }
    }

    /**
     * 孵化 scout
     */
    public static spawnScout(room: MyRoom) {
        if (SpawnController.searchSpawnTaskByRole(room, CreepRoles.scout).length) return

        if (room.memory.state.safe?.state !== RoomSafeState.normal) return

        SpawnController.addSpawnTask(room, {
            role: CreepRoles.scout,
            body: [MOVE, 1],
        })
    }
}
